package com.wenx.v3system.modular.cloud.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wenx.v3core.error.BusinessException;
import com.wenx.v3system.modular.cloud.domain.dto.SysMenuDto;
import com.wenx.v3system.modular.cloud.domain.maps.SysMenuMap;
import com.wenx.v3system.modular.cloud.domain.po.SysMenu;
import com.wenx.v3system.modular.cloud.domain.po.SysRoleMenu;
import com.wenx.v3system.modular.cloud.domain.query.SysMenuQuery;
import com.wenx.v3system.modular.cloud.mapper.SysMenuMapper;
import com.wenx.v3system.modular.cloud.mapper.SysRoleMenuMapper;
import com.wenx.v3system.modular.cloud.service.SysMenuRestService;
import com.wenx.v3system.modular.cloud.service.SysUserPermissionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 系统菜单服务实现类
 * 基于Enhanced RBAC权限模型
 * 提供菜单管理、权限控制和树形结构操作
 * 
 * @author wenx
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
// @DS(DynamicDataSourceConfig.DEFAULT_DATASOURCE)
public class SysMenuRestServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuRestService {

    // 缓存常量
    private static final String MENU_CACHE = "sys:menu";
    private static final String MENU_TREE_CACHE = "sys:menu:tree";
    private static final String USER_MENUS_CACHE = "sys:user:menus";
    private static final String ROLE_MENUS_CACHE = "sys:role:menus";

    // 依赖注入
    private final SysMenuMapper sysMenuMapper;
    private final SysRoleMenuMapper sysRoleMenuMapper;
    private final SysUserPermissionService sysUserPermissionService;

    @Override
    public IPage<?> page(SysMenuQuery query) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<SysMenu>()
                .like(StringUtils.hasText(query.getName()), "name", query.getName())
                .like(StringUtils.hasText(query.getCode()), "code", query.getCode())
                .eq(query.getStatus() != null, "status", query.getStatus())
                .eq(query.getType() != null, "type", query.getType())
                .eq(query.getParentId() != null, "parent_id", query.getParentId())
                .like(StringUtils.hasText(query.getPermissions()), "permissions", query.getPermissions())
                .like(StringUtils.hasText(query.getPath()), "path", query.getPath())
                .eq("deleted", false);

        // 关键词搜索（菜单名称或编码）
        if (StringUtils.hasText(query.getKeyword())) {
            wrapper.and(w -> w.like("name", query.getKeyword())
                    .or()
                    .like("code", query.getKeyword()));
        }

        if (StringUtils.hasText(query.getOrderBy())) {
            // 自定义排序
            if ("desc".equalsIgnoreCase(query.getOrderType())) {
                wrapper.orderByDesc(query.getOrderBy());
            } else {
                wrapper.orderByAsc(query.getOrderBy());
            }
        } else {
            // 默认排序
            wrapper.orderByAsc("sort")
                    .orderByDesc("create_time");
        }

        IPage<SysMenu> result = super.page(new Page<>(query.getCurrent(), query.getSize()), wrapper);
        return result.convert(this::convertToDto);
    }
    

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, MENU_TREE_CACHE}, allEntries = true)
    public void add(SysMenuDto dto) {
        // 验证菜单编码唯一性
        if (existsByCode(dto.getCode(), null)) {
            throw new BusinessException("菜单编码已存在: " + dto.getCode());
        }
        
        SysMenu menu = SysMenuMap.INSTANCE.toPo(dto);
        
        boolean success = super.save(menu);
        if (!success) {
            throw new BusinessException("菜单新增失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, MENU_TREE_CACHE, USER_MENUS_CACHE, ROLE_MENUS_CACHE}, allEntries = true)
    public void delete(Serializable id) {
        SysMenu menu = super.getById(id);
        if (menu == null) {
            throw new BusinessException("菜单不存在，ID: " + id);
        }
        
        // 检查是否有子菜单
        List<SysMenuDto> childMenus = getChildMenus(Long.valueOf(id.toString()));
        if (!childMenus.isEmpty()) {
            throw new BusinessException("存在子菜单，无法删除");
        }
        
        // 检查是否有角色关联此菜单
        QueryWrapper<SysRoleMenu> roleMenuWrapper = new QueryWrapper<>();
        roleMenuWrapper.eq("menu_id", id);
        long roleMenuCount = sysRoleMenuMapper.selectCount(roleMenuWrapper);
        if (roleMenuCount > 0) {
            throw new BusinessException("该菜单已被角色关联，无法删除。请先解除角色关联后再删除");
        }
        
        boolean success = super.removeById(id);
        if (!success) {
            throw new BusinessException("菜单删除失败");
        }
        
        log.info("菜单删除成功，菜单ID: {}, 菜单名称: {}", id, menu.getName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, MENU_TREE_CACHE}, allEntries = true)
    public void update(SysMenuDto dto) {
        if (dto.getId() == null) {
            throw new BusinessException("菜单ID不能为空");
        }
        
        SysMenu existingMenu = super.getById(dto.getId());
        if (existingMenu == null) {
            throw new BusinessException("菜单不存在，ID: " + dto.getId());
        }
        
        // 验证菜单编码唯一性（排除当前菜单）
        if (existsByCode(dto.getCode(), dto.getId())) {
            throw new BusinessException("菜单编码已存在: " + dto.getCode());
        }
        
        // 复制属性
        BeanUtils.copyProperties(dto, existingMenu, "id", "createTime", "createBy");
        // 更新时间由BaseEntity处理
        
        boolean success = super.updateById(existingMenu);
        if (!success) {
            throw new BusinessException("菜单更新失败");
        }
    }

    @Override
    @Cacheable(value = MENU_CACHE, key = "#id")
    public Object get(Serializable id) {
        SysMenu menu = super.getById(id);
        if (menu == null) {
            return null;
        }
        return menu;
    }

    @Override
    @Cacheable(value = MENU_CACHE, key = "'code:' + #code")
    public SysMenuDto getMenuByCode(String code) {
        if (!StringUtils.hasText(code)) {
            throw new BusinessException("菜单编码不能为空");
        }
        
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getCode, code)
               .eq(SysMenu::getDeleted, false);
        
        SysMenu menu = super.getOne(wrapper);
        if (menu == null) {
            return null;
        }
        
        // 使用 SysMenuMap 转换为 DTO
        return SysMenuMap.INSTANCE.toDto(menu);
    }

    @Override
    @Cacheable(value = USER_MENUS_CACHE, key = "#userId")
    public List<SysMenuDto> getUserMenus(Long userId) {
        if (userId == null) {
            throw new BusinessException("用户ID不能为空");
        }
        
        // 获取用户角色ID集合
        Set<Long> roleIds = sysUserPermissionService.getUserRoles(userId);
        if (CollectionUtils.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        
        // 查询角色关联的菜单ID集合
        LambdaQueryWrapper<SysRoleMenu> roleMenuWrapper = new LambdaQueryWrapper<>();
        roleMenuWrapper.in(SysRoleMenu::getRoleId, roleIds);
        
        List<SysRoleMenu> roleMenus = sysRoleMenuMapper.selectList(roleMenuWrapper);
        if (CollectionUtils.isEmpty(roleMenus)) {
            return Collections.emptyList();
        }
        
        // 提取菜单ID集合
        Set<Long> menuIds = roleMenus.stream()
                .map(SysRoleMenu::getMenuId)
                .collect(Collectors.toSet());
        
        // 查询菜单详情
        LambdaQueryWrapper<SysMenu> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.in(SysMenu::getId, menuIds)
                  .eq(SysMenu::getDeleted, false)
                  .eq(SysMenu::getStatus, 1)
                  .orderByAsc(SysMenu::getSort);
        
        List<SysMenu> menus = sysMenuMapper.selectList(menuWrapper);
        if (CollectionUtils.isEmpty(menus)) {
            return Collections.emptyList();
        }
        
        // 转换为DTO
        return SysMenuMap.INSTANCE.toDtoList(menus);
    }

    @Override
    @Cacheable(value = ROLE_MENUS_CACHE, key = "#roleId")
    public List<SysMenuDto> getRoleMenus(Long roleId) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        
        // 查询角色关联的菜单ID集合
        LambdaQueryWrapper<SysRoleMenu> roleMenuWrapper = new LambdaQueryWrapper<>();
        roleMenuWrapper.eq(SysRoleMenu::getRoleId, roleId);
        
        List<SysRoleMenu> roleMenus = sysRoleMenuMapper.selectList(roleMenuWrapper);
        if (CollectionUtils.isEmpty(roleMenus)) {
            return Collections.emptyList();
        }
        
        // 提取菜单ID集合
        Set<Long> menuIds = roleMenus.stream()
                .map(SysRoleMenu::getMenuId)
                .collect(Collectors.toSet());
        
        // 查询菜单详情
        LambdaQueryWrapper<SysMenu> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.in(SysMenu::getId, menuIds)
                  .eq(SysMenu::getDeleted, false)
                  .eq(SysMenu::getStatus, 1)
                  .orderByAsc(SysMenu::getSort);
        
        List<SysMenu> menus = sysMenuMapper.selectList(menuWrapper);
        if (CollectionUtils.isEmpty(menus)) {
            return Collections.emptyList();
        }
        
        // 转换为DTO
        return SysMenuMap.INSTANCE.toDtoList(menus);
    }

    @Override
    @Cacheable(value = MENU_TREE_CACHE, key = "'tree:' + (#parentId != null ? #parentId : 'root')")
    public List<SysMenuDto> getMenuTree(Long parentId) {
        // 获取所有菜单数据（包括禁用的菜单）
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getDeleted, false)
               .orderByAsc(SysMenu::getSort);
        
        List<SysMenu> allMenus = super.list(wrapper);
        
        // 转换为DTO
        List<SysMenuDto> allMenuDtos = allMenus.stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
        
        // 构建树形结构
        return buildMenuTree(allMenuDtos, parentId);
    }
    
    /**
     * 构建菜单树形结构
     * 
     * @param allMenus 所有菜单列表
     * @param parentId 父菜单ID
     * @return 树形菜单列表
     */
    private List<SysMenuDto> buildMenuTree(List<SysMenuDto> allMenus, Long parentId) {
        return allMenus.stream()
                .filter(menu -> {
                    if (parentId == null) {
                        return menu.getParentId() == null || menu.getParentId().equals(0L);
                    } else {
                        return parentId.equals(menu.getParentId());
                    }
                })
                .map(menu -> {
                    // 递归设置子菜单
                    List<SysMenuDto> children = buildMenuTree(allMenus, menu.getId());
                    menu.setChildren(children.isEmpty() ? null : children);
                    return menu;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<SysMenuDto> getChildMenus(Long parentId) {
        if (parentId == null) {
            throw new BusinessException("父菜单ID不能为空");
        }
        
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getDeleted, false)
               .eq(SysMenu::getParentId, parentId)
               .orderByAsc(SysMenu::getSort);
        
        List<SysMenu> childMenus = sysMenuMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(childMenus)) {
            return Collections.emptyList();
        }
        
        // 使用 SysMenuMap 转换为 DTO 列表
        return SysMenuMap.INSTANCE.toDtoList(childMenus);
    }

    @Override
    public boolean existsByCode(String code, Long excludeId) {
        if (!StringUtils.hasText(code)) {
            return false;
        }
        
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getCode, code)
               .eq(SysMenu::getDeleted, false);
        
        if (excludeId != null) {
            wrapper.ne(SysMenu::getId, excludeId);
        }
        
        return super.count(wrapper) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, USER_MENUS_CACHE}, allEntries = true)
    public void enableMenu(Long menuId) {
        updateMenuStatus(menuId, 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, USER_MENUS_CACHE}, allEntries = true)
    public void disableMenu(Long menuId) {
        updateMenuStatus(menuId, 0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, MENU_TREE_CACHE}, allEntries = true)
    public void moveMenu(Long menuId, Long targetParentId, Integer targetSort) {
        if (menuId == null) {
            throw new BusinessException("菜单ID不能为空");
        }
        
        SysMenu menu = sysMenuMapper.selectById(menuId);
        if (menu == null) {
            throw new BusinessException("菜单不存在，ID: " + menuId);
        }
        
        // 检查目标父菜单是否存在（如果不为null）
        if (targetParentId != null) {
            SysMenu parentMenu = sysMenuMapper.selectById(targetParentId);
            if (parentMenu == null) {
                throw new BusinessException("目标父菜单不存在，ID: " + targetParentId);
            }
        }
        
        // 更新菜单的父级和排序
        menu.setParentId(targetParentId);
        if (targetSort != null) {
            menu.setSort(targetSort.longValue()); // 转换Integer为Long
        }
        
        int result = sysMenuMapper.updateById(menu);
        if (result <= 0) {
            throw new BusinessException("菜单移动失败");
        }
        
        log.info("菜单移动成功: menuId={}, targetParentId={}, targetSort={}", menuId, targetParentId, targetSort);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {MENU_CACHE, MENU_TREE_CACHE}, allEntries = true)
    public void updateMenuSorts(List<SysMenuDto> menuSorts) {
        if (menuSorts == null || menuSorts.isEmpty()) {
            throw new BusinessException("菜单排序列表不能为空");
        }
        
        List<SysMenu> updateList = new ArrayList<>();
        
        for (SysMenuDto menuDto : menuSorts) {
            if (menuDto.getId() == null) {
                log.warn("跳过无效的菜单排序项，菜单ID为空");
                continue;
            }
            
            SysMenu menu = sysMenuMapper.selectById(menuDto.getId());
            if (menu == null) {
                log.warn("菜单不存在，跳过排序更新，菜单ID: {}", menuDto.getId());
                continue;
            }
            
            // 更新排序字段
            if (menuDto.getSort() != null) {
                menu.setSort(menuDto.getSort());
                updateList.add(menu);
            }
        }
        
        if (updateList.isEmpty()) {
            log.warn("没有有效的菜单需要更新排序");
            return;
        }
        
        // 批量更新
        for (SysMenu menu : updateList) {
            int result = sysMenuMapper.updateById(menu);
            if (result <= 0) {
                throw new BusinessException("菜单排序更新失败，菜单ID: " + menu.getId());
            }
        }
        
        log.info("批量更新菜单排序成功，更新数量: {}", updateList.size());
    }

    /**
     * 更新菜单状态
     */
    private void updateMenuStatus(Long menuId, Integer status) {
        if (menuId == null) {
            throw new BusinessException("菜单ID不能为空");
        }
        
        SysMenu menu = super.getById(menuId);
        if (menu == null) {
            throw new BusinessException("菜单不存在，ID: " + menuId);
        }
        
        menu.setStatus(status);
        // 更新时间由BaseEntity处理
        
        boolean success = super.updateById(menu);
        if (!success) {
            throw new BusinessException("菜单状态更新失败");
        }
    }
    
    /**
     * 将实体转换为DTO
     */
    private SysMenuDto convertToDto(SysMenu menu) {
        if (menu == null) {
            return null;
        }
        
        SysMenuDto dto = new SysMenuDto();
        BeanUtils.copyProperties(menu, dto);
        return dto;
    }
}
